package utils

import android.util.Log
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.*

object L {

    enum class LogLevel {
        ERROR {
            override val value: Int
                get() = 0
        },
        WARN {
            override val value: Int
                get() = 1
        },
        INFO {
            override val value: Int
                get() = 2
        },
        DEBUG {
            override val value: Int
                get() = 3
        };

        abstract val value: Int
    }

    private var TAG = "[SILENCE]"

    // 日志的等级，可以进行配置，最好在Application中进行全局的配置
    private var logLevel = LogLevel.DEBUG

    @JvmStatic
    fun init(clazz: Class<*>) {
        TAG = clazz.simpleName
    }

    /**
     * 支持用户自己传tag，可扩展性更好
     * @param tag
     */
    @JvmStatic
    fun init(tag: String) {
        TAG = tag
    }

    @JvmStatic
    fun e(msg: String) {
        if (LogLevel.ERROR.value <= logLevel.value) {


            if (msg.isNotBlank()) {
                val m = msg.replace("\n".toRegex(), "\n║ ")
                val s = getMethodNames()
                Log.e("", String.format(s, m))
            }
        }
    }

    @JvmStatic
    fun w(msg: String) {
        if (LogLevel.WARN.value <= logLevel.value) {

            if (msg.isNotBlank()) {
                val m = msg.replace("\n".toRegex(), "\n║ ")
                val s = getMethodNames()
                Log.e("", String.format(s, m))
            }
        }
    }

    @JvmStatic
    fun i(msg: String) {
        if (LogLevel.INFO.value <= logLevel.value) {
            val m = msg.replace("\n".toRegex(), "\n║ ")
            if (msg.isNotBlank()) {
                val s = getMethodNames()
                Log.i("", String.format(s, m))
            }

        }
    }

    @JvmStatic
    fun d(msg: String) {
        if (LogLevel.DEBUG.value <= logLevel.value) {

            if (msg.isNotBlank()) {
                val m = msg.replace("\n".toRegex(), "\n║ ")
                val s = getMethodNames()
                Log.d("", String.format(s, m))
            }
        }
    }

    @JvmStatic
    fun getJson(j: String) {
        var json = j

        if (json.isBlank()) {
            d("Empty/Null json content")
            return
        }

        try {
            json = json.trim { it <= ' ' }

            if (json.startsWith("{")) {
                val jsonObject = JSONObject(json)
                var message = jsonObject.toString(LoggerPrinter.JSON_INDENT)
                message = message.replace("\n".toRegex(), "\n║ ")
                val s = getMethodNames()
                Log.i("", String.format(s, message))
                return
            }
            if (json.startsWith("[")) {
                val jsonArray = JSONArray(json)
                var message = jsonArray.toString(LoggerPrinter.JSON_INDENT)
                message = message.replace("\n".toRegex(), "\n║ ")
                val s = getMethodNames()
                Log.i("", String.format(s, message))
                return
            }
            e("Invalid Json")
        } catch (e: JSONException) {
            e("Invalid Json")
        }

    }

    private fun getMethodNames(): String {
        //获取线程信息
        val sElements = Thread.currentThread().stackTrace

        var stackOffset = LoggerPrinter.getStackOffset(sElements)

        ///获取日期信息
        val data = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(Date())

        stackOffset++
        val builder = StringBuilder()
        builder.append(LoggerPrinter.TOP_BORDER).append("\r\n")
            // 添加当前线程名
            .append("║ $TAG [$data] THREAD: ${Thread.currentThread().name}").append("\r\n")
            .append(LoggerPrinter.MIDDLE_BORDER).append("\r\n")
            // 添加类名、方法名、行数
            .append("║ ")
            .append(sElements[stackOffset].className)
            .append(".")
            .append(sElements[stackOffset].methodName)
            .append(" ")
            .append(" (")
            .append(sElements[stackOffset].fileName)
            .append(":")
            .append(sElements[stackOffset].lineNumber)
            .append(")")
            .append("\r\n")
            .append(LoggerPrinter.MIDDLE_BORDER).append("\r\n")
            // 添加打印的日志信息
            .append("║ ").append("%s").append("\r\n")
            .append(LoggerPrinter.BOTTOM_BORDER).append("\r\n")
        return builder.toString()
    }

}

object LoggerPrinter {
    private const val MIN_STACK_OFFSET = 3

    private const val TOP_LEFT_CORNER = '╔'
    private const val BOTTOM_LEFT_CORNER = '╚'
    private const val MIDDLE_CORNER = '╟'
    private const val DOUBLE_DIVIDER = "════════════════════════════════════════════"
    private const val SINGLE_DIVIDER = "────────────────────────────────────────────"
    val TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER
    val BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER
    val MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER

    const val JSON_INDENT = 2

    fun getStackOffset(trace: Array<StackTraceElement>): Int {
        var i = MIN_STACK_OFFSET
        while (i < trace.size) {
            val e = trace[i]
            val name = e.className
            if (name != LoggerPrinter::class.java.name && name != L::class.java.name) {
                return --i
            }
            i++
        }
        return -1
    }
}